package agencia;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;

import agencia.exceptions.LugarInsuficienteException;
import agencia.exceptions.ReservaNoConfirmadaException;

import com.agencia.ws.cliente.Pasajero;
import com.agencia.ws.cliente.VueloWs;


public class ReservaDePaquete {
	
	private Paquete paquete;
	private Collection<Pasajero> pasajeros;
	private Date diaReserva = new Date();
	private double precioTotal ;
	private PlanDePago planPago;
	protected Collection<ReservaVuelo> reservaVuelos = new ArrayList<ReservaVuelo>();
	
	final float porcentajeReserva = Float.valueOf("0.3");
	final float porcentajeDevolucion = Float.valueOf("0.2");
	final int horasPreCancelacion = 96;
	
	public enum Estado 
	{
		Abierta,
		Confirmada,
		Cancelada,
		Cerrada,
	};
	
	private Estado estado;
	
	public ReservaDePaquete (Paquete paquete, Collection<Pasajero> pasajeros){
		this.paquete = paquete;
		this.pasajeros = pasajeros;
		
		this.precioTotal = this.paquete.determinarPrecio() * this.pasajeros.size();	
		
		for (Iterator<VueloWs> iVuelo = this.paquete.vuelos.iterator(); iVuelo.hasNext();) {
			VueloWs vuelo= iVuelo.next();
			this.reservaVuelos.add(new ReservaVuelo(vuelo));
		}
		this.estado = Estado.Abierta;		
	}
	
	public void ConfirmarReserva(int cantidadPagos) throws LugarInsuficienteException{	
			
		this.diaReserva = new Date();
		this.DefinirPlanDePago(cantidadPagos);
		
		if (this.ConsultarDisponibilidad())
		{
			this.paquete.Reservar(this.pasajeros.size());
					
			for (Iterator<ReservaVuelo> iReservaVuelo = this.reservaVuelos.iterator(); iReservaVuelo.hasNext();) {
				ReservaVuelo reservaVuelo= iReservaVuelo.next();
				reservaVuelo.reservar(this.pasajeros);				
			}
			
			this.estado=Estado.Confirmada;
		}
		else
			throw new LugarInsuficienteException("No existen lugares suficientes para concretar la reserva"); 		
	}
		
	
	public double CancelarReserva() throws ReservaNoConfirmadaException {
		if ((this.estado == Estado.Confirmada) || (this.estado == Estado.Abierta)){
			// Se calclulan las horas desde la fecha de reserva.
			Date today = new Date();
			int horasDesdeReserva = (int) ((today.getTime() - this.diaReserva.getTime()) / (1000 * 60 * 60));
					
			this.paquete.CancelarReserva(this.pasajeros.size());	
	//		VueloWs.cancelarReserva(this.reservasVuelos);
			for (Iterator<ReservaVuelo> iReservaVuelo = this.reservaVuelos.iterator(); iReservaVuelo.hasNext();) {
				ReservaVuelo reservaVuelo= iReservaVuelo.next();
				reservaVuelo.cancelar(this.pasajeros);				
			}
			
			this.estado=Estado.Cancelada;
			
			//Devuelve el importe a devolver por la cancelacion
			if (horasDesdeReserva > horasPreCancelacion)
				return 0;
			else
				return (Math.round(this.getCostoReserva() * porcentajeDevolucion));
		}
		else
			throw new ReservaNoConfirmadaException("La reserva no se encuentra en estado Confirmada");
	}

	private void CerrarReserva() throws LugarInsuficienteException{
		//VueloWs.comprarPasaje(this.reservasVuelos);
		for (Iterator<ReservaVuelo> iReservaVuelo = this.reservaVuelos.iterator(); iReservaVuelo.hasNext();) {
			ReservaVuelo reservaVuelo= iReservaVuelo.next();
			reservaVuelo.comprar(this.pasajeros);				
		}
		this.estado=Estado.Cerrada;
	}
	
	public Date getDiaReserva (){
		return this.diaReserva;
	}
	
	public double getPrecioTotal(){
		return Math.round(this.precioTotal);
	}
	
	public double getCostoReserva(){
		return Math.round(this.precioTotal * porcentajeReserva);
	}

	public boolean ConsultarDisponibilidad(){
		if (this.paquete.getLugaresLibres()< this.pasajeros.size())			
			return false;
		else
			return true;
	}
	
	public void DefinirPlanDePago(int cantidadCuotas)
	{
		if(cantidadCuotas>1)
			this.planPago = new PlanCuotas(this.getPrecioTotal() - this.getCostoReserva(),cantidadCuotas);
		else
			this.planPago = new PlanContado(this.getPrecioTotal() - this.getCostoReserva());		
	}

	public void Pagar()throws ReservaNoConfirmadaException, LugarInsuficienteException, Exception{
		
		if (this.estado == Estado.Confirmada){
			this.planPago.Pagar();
		
			if (this.planPago.PlanCerrado())
			this.CerrarReserva();
		}
		else
			throw new ReservaNoConfirmadaException("La reserva no se encuentra en estado Confirmada");
	}
	
	public double getMonto() throws Exception{
		if (this.estado != Estado.Cerrada)
			return Math.round(this.planPago.GetMonto());
		else
			return 0;
	}
		
	public String getEstadoStr()
	{
		return estado.toString();
	}
	
	public Estado getEstado()
	{
		return estado;
	}
	
	public String getNombre(){
		return this.paquete.getNombre();
	}
	
	public int getCantidadPasajeros(){
		return this.paquete.getCantidadPasajeros();
	}

	public Collection<Pasajero> getPasajeros() {
		return pasajeros;
	}
	
	public int getCantPagosPendientes(){
		return this.planPago.getCantPagosPendientes();
	}

	public int getCantPagos(){
		return this.planPago.getCantPagos();
	}
}
